/**
 * Copyright c FOUNDER  2005 All Rights Reserved.
 * DataAccessor.java
 */
package com.iori.common.db.dbctrl;

import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.torque.TorqueException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.iori.common.db.DbUtil;

/**
 * [クラス名]<br>
 * データアクセッサー<br>
 * <br>
 * [機能概要]<br>
 * SQL文をカプセル化した、データベースにアクセスするクラス。<br>
 * このクラスはSQL文単位にコミットを発行するが、 複数のDataAccessorクラスを同一トランザクションで扱う場合は
 * StatementControllerクラスと併用して使用する。<br>
 * <br>
 * [変更履歴]<br>
 * 2005/07/08 ver1.00 新規作成 zhanjc<br>
 * <br>
 * 2007/03/08 ver1.10 oracle date getObject -> getTimestamp 修正 zhanjc<br>
 * 2007/04/23 ver1.20 定義されたSQL文は同時に#AB #ABCが存在すれば、取り替えるエラーの問題の修正が出てきます weifeng<br>
 *
 * @see jp.co.pia.bety.front.common.db.dbctrl.StatementController
 *
 * @author zhanjc
 * @version 1.20
 */
public class DataAccessor implements IAccessor {
	/**
	 * ログ出力用のインスタンス生成。 log输出的instance
	 */
	protected static Log logger = LogFactory.getLog(DataAccessor.class);

	/**
	 * SQL文のタイプを表す定数。SELECT文を識別します。
	 */
	public static final int QUERY = 0;

	/**
	 * SQL文のタイプを表す定数。INSERT文、UPDATE文、DELETE文を識別します。
	 */
	public static final int DML = 1;

	/**
	 * SQL文のタイプを表す定数。ストアドファンクション、ストアドプロシージャを識別します。
	 */
	public static final int STORED = 2;

	/**
	 * 検索のSQL文が終わった後、SQL文を得る
	 */
	private String querySql = null;

	/**
	 * SQLリストのid
	 */
	protected String listName = null;

	/**
	 * SQL文のid
	 */
	protected String id = null;

	/**
	 * コネクトするDB名
	 */
	protected String dbName = null;

	/**
	 * SQLスキーマ名
	 */
	protected String schemaName = null;

	/**
	 * パラメータ（バインド変数）とその<b>値</b>のマップ
	 */
	protected Map parameterList = null;

	/**
	 * アウトプットパラメータ（変数名）とその<b>型</b>のマップ
	 */
	protected Map outputParameterList = new HashMap();

	/**
	 * SQLファイルのSQL文をパラメータ設定用SQLに変換し保持
	 */
	protected PreparedSql preparedSql = null;

	/**
	 * 次回読込情報、次回読込のレコード順番
	 */
	protected Integer nextRecord = null;

	/**
	 * batch用PreparedStatement
	 */
	protected PreparedStatement batchPst = null;

	/**
	 * batch用Connection
	 */
	protected Connection batchConn = null;

	/**
	 * 直接利用ResultSet处理检索结果的连接
	 */
	protected Connection queryConnection = null;

	/**
	 * 直接利用ResultSet处理检索结果
	 */
	protected ResultSet queryResultSet = null;

	/**
	 * 直接利用ResultSet处理检索结果
	 */
	private PreparedStatement queryStatement = null;

	/**
	 * database-version
	 */
	protected static final String oracle10g = "oracle10g";

	/**
	 * parameterListを構築する時使用されたcomparator比べるルールとStringを比べるルールは逆になります。
	 */
	// protected Comparator comparator = new Comparator() {
	// public int compare(Object o1, Object o2) {
	// String s1 = o1.toString();
	// String s2 = o2.toString();
	// int result = s1.compareTo(s2);
	// return result * (-1);
	// }
	// };
	/**
	 * 指定されたSQL文のidからSQL文を取得し、パラメータ設定のための準備を行う。<br>
	 * SQL文は一意の名前をもったキーによりSQLリストで複数管理される。 また、SQLリストも同様に一意の名前のキーにより複数管理される。<br>
	 * データベースへアクセスする場合は、SQLのリスト名とその中にあるSQL文のIDを指定する。<br>
	 * さらに、Torque.propertiesに設定されている設定名称を指定し、接続するデータベースを決定する。
	 *
	 * @param sqlListName
	 *            SQLリストのid
	 * @param sqlId
	 *            SQL文のid
	 * @param dbName
	 *            接続するデータベース名
	 */
	public DataAccessor(String sqlListName, String sqlId, String dbName) {
		this.parameterList = new HashMap();
		this.listName = sqlListName;
		this.id = sqlId;
		this.dbName = dbName;
		this.init();
	}

	/**
	 * 指定されたSQL文のidからSQL文を取得し、パラメータ設定のための準備を行う。<br>
	 * SQL文は一意の名前をもったキーによりSQLリストで複数管理される。 また、SQLリストも同様に一意の名前のキーにより複数管理される。<br>
	 * データベースへアクセスする場合は、SQLのリスト名とその中にあるSQL文のIDを指定する。<br>
	 * さらに、Torque.propertiesに設定されている設定名称を指定し、接続するデータベースを決定する。
	 *
	 * @param sqlListName
	 *            SQLリストのid
	 * @param sqlId
	 *            SQL文のid
	 * @param dbName
	 *            接続するデータベース名
	 * @param schemaNameValue
	 *            スキーマ名
	 */
	public DataAccessor(String sqlListName, String sqlId, String dbName,
			String schemaNameValue) {
		this.parameterList = new HashMap();
		this.listName = sqlListName;
		this.id = sqlId;
		this.dbName = dbName;
		this.schemaName = schemaNameValue;
		this.init();
	}

	/**
	 * 初期化処理。（コンストラクタにより呼び出される）<br>
	 * SQL文を取得し、パラメータの設定準備を行なう。
	 */
	protected void init() {
		SqlList list = SqlListCollection.get(this.listName);
		if (list != null) {
			if (!"".equals(this.id)) {
				this.preparedSql = list.getSql(this.id);
				if (this.preparedSql == null) {
					logger.error("初期化処理 Failed!");
				}
			}
		} else {
			this.preparedSql = null;
			logger.error("初期化処理 Failed!");
		}
	}

	/**
	 * SQL文のidを取得する。
	 *
	 * @return SQL文のid
	 */
	public String getId() {
		return this.id;
	}

	/**
	 * webbk.propertiesの設定名称（DB schema 接続名称）を取得する。
	 *
	 * @return webbk.propertiesの設定名称（DB接続名称）
	 */
	public String getDestination() {
		return this.dbName;
	}

	/**
	 * SQLスキーマ名を取得する。
	 *
	 * @return スキーマ名
	 */
	public String getSchemaName() {
		return this.schemaName;
	}

	/**
	 * 最後に実行したSQL文。SQL実行前に呼び出すとnullを返す。
	 *
	 * @return value 最後に実行したSQL文
	 */
	public String getSql() {
		return this.preparedSql.getSql();
	}

	/**
	 * ＤＢ処理エラーの時、復旧用のSQL文と対応なパラメータを取得する。
	 *
	 * @return value 復旧用のSQL文
	 */
	public String getRecoverSql() {
		// String sql = this.preparedSql.getCompleteSql();
		// if (sql == null) {
		// preparedSql.prepareParameter(this.parameterList);
		// preparedSql.setRecoverParameter(this.parameterList);
		// sql = this.preparedSql.getCompleteSql();
		// }
		return this.preparedSql.getSql();
	}

	/**
	 * 最後に実行したSQLのパラメータ名リスト。SQL実行前に呼び出すとnullを返す。
	 *
	 * @return value 最後に実行したSQLのパラメータ名リスト
	 */
	public Map getParameterList() {
		return this.parameterList;
	}

	/**
	 * アウトプットパラメータ（変数名）とその<b>型</b>のマップ。
	 *
	 * @return value Outputのパラメータ名リスト
	 */
	public Map getOutputParameterList() {
		return this.outputParameterList;
	}

	/**
	 * アウトプットパラメータ（変数名）とその<b>型</b>のマップ。
	 *
	 * @return value Outputのパラメータ
	 */
	public Object getOutputParameter(String key) {
		return this.outputParameterList.get(key);
	}

	/**
	 * 指定されたパラメータ名の値を取得する。
	 *
	 * @param key
	 *            パラメータの名前
	 *
	 * @return パラメータ値
	 */
	public Object getParameter(String key) {
		return this.parameterList.get(key);
	}

	/**
	 * 指定したパラメータ名で値を設定する。<br>
	 * 既に同一のパラメータ名が存在する場合は、値が上書きされる。
	 *
	 * @param key
	 *            パラメータの名前
	 * @param value
	 *            パラメータの値
	 */
	public void setParameter(String key, Object value) {
		this.parameterList.put(key, value);
	}

	/**
	 * 指定されたパラメータ名の値を削除する。
	 *
	 * @param key
	 *            パラメータの名前
	 */
	public void removeParameter(String key) {
		this.parameterList.remove(key);
	}

	/**
	 * 指定されたパラメータ名と型をアウトプットパラメータとして登録する。<br>
	 * OUTパラメータがある場合は、SQL実行前にこのメソッドを呼び出し、 OUTパラメータの型をあらかじめ指定しなくてはならない。
	 *
	 * @param key
	 *            パラメータの名前
	 * @param sqltype
	 *            JDBCが使用するパラメータの型（java.sql.Typesを参照）
	 */
	public void registOutputParameter(String key, int sqltype) {
		this.outputParameterList.put(key, new Integer(sqltype));
	}

	/**
	 * パラメータとOUTパラメータをクリアする。
	 */
	public void clearParameter() {
		this.parameterList.clear();
		this.outputParameterList.clear();
	}

	/**
	 * SELECT文を発行する。<br>
	 * 結果は以下のように定義されたDOMを返す。 <resultset> <head> <colname value="カラムラベル名" /> ・・・
	 * </head> <row id="0"> <col name="カラム名" value="カラム値" /> ・・・ </row> ・・・
	 * </resultset>
	 *
	 * @return Document SELECT結果のDOMドキュメント
	 * @throws SQLException
	 * @throws TorqueException
	 * @throws ParserConfigurationException
	 * @throws IOException
	 */
	public Document executeQueryAsDom() throws Exception {
		long start = System.currentTimeMillis();
		Connection connection = null;
		Document result = null;

		try {
			connection = DbUtil.beginOptional(this.dbName, false);
			// データーベースーユーザ名を設定する
			connection = setSchemaForConnection(connection);
			result = executeQueryAsDom(connection);
		} catch (Exception e) {
			logger.error(e.getMessage());
			throw e;
		} finally {
			DbUtil.closeConnection(connection);
			logger.debug("TimeMillis=" + (System.currentTimeMillis() - start));
		}

		return result;
	}

	/**
	 * SELECT文を発行する。<br>
	 * 結果は以下のように定義されたDOMを返す。 <resultset> <head> <colname value="カラムラベル名" /> ・・・
	 * </head> <row id="0"> <col name="カラム名" value="カラム値" /> ・・・ </row> ・・・
	 * </resultset>
	 *
	 * @param connection
	 *            データベースへのコネクション
	 *
	 * @return Document SELECT結果のDOMドキュメント
	 * @throws ParserConfigurationException
	 *
	 * @exception Exception
	 *                例外
	 */
	public Document executeQueryAsDom(Connection connection) throws Exception {

		Document result = null;
		Element root = null;

		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			result = builder.newDocument();
			root = result.createElement("resultset");
			root.setAttribute("sqlid", this.getId());
			result.appendChild(root);
		} catch (ParserConfigurationException e) {
			throw e;
		}

		try {
			preparedSql.prepareParameter(this.parameterList);
			PreparedStatement statement = connection
					.prepareStatement(preparedSql.getSql());
			this.preparedSql.setParameter(statement, this.parameterList);
			ResultSet resultSet = statement.executeQuery();
			// ヘッダーエレメントの作成
			ResultSetMetaData meta = resultSet.getMetaData();
			Element head = result.createElement("head");
			for (int j = 1; j < meta.getColumnCount() + 1; j++) {
				Element colname = result.createElement("colname");
				colname.setAttribute("value", meta.getColumnLabel(j));
				head.appendChild(colname);
			}
			root.appendChild(head);
			// レコードエレメントの作成
			int count = 0;
			while (resultSet.next()) {
				Element record = result.createElement("row");
				record.setAttribute("id", Integer.toString(count));
				for (int i = 1; i < meta.getColumnCount() + 1; i++) {
					Element column = result.createElement("col");
					column.setAttribute("name", meta.getColumnLabel(i));
					if (resultSet.getObject(i) == null) {
						column.setAttribute("value", "");
					} else {
						// Edited by zhanjc 2007/03/08 Start
						// if
						// (DBEnvConstant.getConfig("database.version").trim().equalsIgnoreCase(oracle10g))
						// {
						if (resultSet.getObject(i) instanceof java.sql.Date) {
							column.setAttribute("value", DbUtil
									.objectToString(resultSet.getTimestamp(i)));
						} else {
							column.setAttribute("value", DbUtil
									.objectToString(resultSet.getObject(i)));
						}
						// } else {
						// column.setAttribute("value",
						// DbUtil.objectToString(resultSet.getObject(i)));
						// }
						// Edited by zhanjc 2007/03/08 End
					}
					record.appendChild(column);
				}
				root.appendChild(record);
				count++;
			}
			resultSet.close();
		} catch (SQLException e) {
			throw e;
		} catch (IOException e) {
			throw e;
		}

		return result;
	}

	/**
	 * SELECT文を発行し、ロールバックする。<br>
	 * 結果をListで返す。Listの各要素はMapが格納されており、 keyにColumnLabelがvalueにObjectが設定されている。<br>
	 * key ： ラベル名 value ： カラム値
	 *
	 * @return List SELECT結果のList
	 */
	public List executeQueryAsList() throws Exception {
		return executeQueryAsList(0, 0, false);
	}

	public List executeQueryAsList(Connection conn) throws Exception {
		return executeQueryAsList(conn, 0, 0, false);
	}

	// added by wsh 2005-12-05 start
	/**
	 * 结果列表中保存的HashMap的value为String类型
	 *
	 * SELECT文を発行し、ロールバックする。<br>
	 * 結果をListで返す。Listの各要素はMapが格納されており、 keyにColumnLabelがvalueにObjectが設定されている。<br>
	 * key ： ラベル名 value ： カラム値
	 *
	 * @return List SELECT結果のList
	 */
	public List executeQueryAsListEx() throws Exception {
		return executeQueryAsList(0, 0, true);
	}

	// added by wsh 2005-12-05 end

	/**
	 * SELECT文を発行し、ロールバックする。<br>
	 * 結果をListで返す。Listの各要素はMapが格納されており、 keyにColumnLabelがvalueにObjectが設定されている。<br>
	 * key ： ラベル名 value ： カラム値
	 *
	 * @param startRecInd
	 *            開始のレコード索引、１は一番目レコード
	 * @param length
	 *            取得しようレコード数
	 * @param bToStr
	 *            文字列－convert
	 *
	 * @return List SELECT結果のList
	 */
	public List executeQueryAsList(int startRecInd, int length, boolean bToStr)
			throws Exception {
		long start = System.currentTimeMillis();
		Connection connection = null;
		List result = null;
		try {
			connection = DbUtil.beginOptional(this.dbName, false);
			// データーベースーユーザ名を設定する
			connection = setSchemaForConnection(connection);
			result = executeQueryAsList(connection, startRecInd, length, bToStr);
		} catch (Exception e) {
			throw e;
		} finally {
			DbUtil.closeConnection(connection);
			logger.debug("TimeMillis=" + (System.currentTimeMillis() - start));
		}
		return result;
	}

	// added by wsh 2005-12-05 start
	public List executeQueryAsList(int startRecInd, int length)
			throws Exception {
		return executeQueryAsList(startRecInd, length, false);
	}

	// added by wsh 2005-12-05 end

	/**
	 * SELECT文を発行し、ロールバックする。<br>
	 * 結果をListで返す。Listの各要素はMapが格納されており、 keyにColumnLabelがvalueにObjectが設定されている。<br>
	 * key ： ラベル名 value ： カラム値 列名を取得したい場合はcolumnNamesにListを渡すこと。
	 *
	 * @param connection
	 *            データベースへのコネクション
	 * @param startRecInd
	 *            開始のレコード索引、１は一番目レコード
	 * @param length
	 *            取得しようレコード数、０は開始レコードからの全部レコード
	 * @param bToStr
	 *            文字列－convert
	 *
	 * @return List SELECT結果のList
	 *
	 * @exception SQLException
	 *                sql例外
	 * @exception IOException
	 *                IO例外
	 */
	public List executeQueryAsList(Connection connection, int startRecInd,
			int length, boolean bToStr) throws SQLException, IOException {
		nextRecord = null;
		List result = null;

		try {
			preparedSql.prepareParameter(this.parameterList);
			// SQLを実行する
			PreparedStatement statement = connection
					.prepareStatement(preparedSql.getSql());
			querySql = this.preparedSql.setParameter(statement,
					this.parameterList);
			System.out.println("&SQL=" + querySql.replaceAll("(\\s)+", " "));
			ResultSet resultSet = statement.executeQuery();
			ResultSetMetaData meta = resultSet.getMetaData();
			result = new ArrayList();
			int i = 0, count = meta.getColumnCount() + 1;
			Map record = null;
			// start前のレコードをスキップ
			if (startRecInd > 1) { // ？いまのドライバはabsoluteを使用できない
				for (int ind = 1; ind < startRecInd; ind++) {
					resultSet.next();
				}
			}
			int size = 0;
			boolean oversize = false;
			while (resultSet.next()) {
				record = new HashMap();
				for (i = 1; i < count; i++) {
					// modified by wsh 2005-12-05 start
					if (bToStr) {
						record.put(meta.getColumnLabel(i), zNull(resultSet
								.getString(i)));
					} else {
						// Edited by zhanjc 2007/03/08 Start
						// if
						// (DBEnvConstant.getConfig("database.version").trim().equalsIgnoreCase(oracle10g))
						// {
						if (resultSet.getObject(i) instanceof java.sql.Date) {
							record.put(meta.getColumnLabel(i), resultSet
									.getTimestamp(i));
						} else {
							record.put(meta.getColumnLabel(i), resultSet
									.getObject(i));
						}
						// } else {
						// record.put(meta.getColumnLabel(i),
						// resultSet.getObject(i));
						// }
						// Edited by zhanjc 2007/03/08 End
					}
					// modified by wsh 2005-12-05 end
				}
				result.add(record);
				size++;
				// 取得したレコード数が指定数を超える
				if (length > 0 && size >= length) {
					oversize = true;
					break;
				}
			}
			if (oversize && resultSet.next()) {
				// 次回読込情報を設定する
				nextRecord = new Integer(size + 1);
			}
			resultSet.close();
			statement.close();
			logger.debug("Count=" + result.size());
		} catch (SQLException e) {
			e.setNextException(new SQLException(e.getMessage() + "&SQL="
					+ querySql.replaceAll("(\\s)+", " ")));
			throw e;
		} catch (IOException e) {
			throw e;
		}

		return result;
	}

	// added by wsh 2005-12-05 start
	public List executeQueryAsList(Connection connection, int startRecInd,
			int length) throws SQLException, IOException {
		return executeQueryAsList(connection, startRecInd, length, false);
	}

	// added by wsh 2005-12-05 end

	// added by wsh 2007-10-19 start
	public String getExeSql() {
		preparedSql.prepareParameter(this.parameterList);
		return preparedSql.getSql();
	}

	// added by wsh 2005-10-19 end

	// added by Liuww 2007-11-05 start
	/**
	 * SELECT文を発行し、ロールバックする。
	 *
	 * @exception SQLException
	 *                sql例外
	 */
	public void executeQuery() throws Exception {
		long start = System.currentTimeMillis();

		try {
			queryConnection = DbUtil.beginOptional(this.dbName, false);
			executeQuery(queryConnection);
		} catch (Exception e) {
			throw e;
		} finally {
			logger.debug("db query TimeMillis="
					+ (System.currentTimeMillis() - start));
		}
	}

	/**
	 * SELECT文を発行し、ロールバックする。
	 *
	 * @param connection
	 *            データベースへのコネクション
	 *
	 * @exception SQLException
	 *                sql例外
	 */
	public void executeQuery(Connection connection) throws SQLException,
			IOException {
		try {
			preparedSql.prepareParameter(this.parameterList);
			// SQLを実行する
			queryStatement = connection.prepareStatement(preparedSql.getSql());
			querySql = this.preparedSql.setParameter(queryStatement,
					this.parameterList);
			queryResultSet = queryStatement.executeQuery();
		} catch (SQLException e) {
			e.setNextException(new SQLException(e.getMessage() + "&SQL="
					+ querySql.replaceAll("(\\s)+", " ")));
			throw e;
		} catch (IOException e) {
			throw e;
		}
	}

	/**
	 * ResultSet Object return
	 */
	public ResultSet getResultSet() {
		return queryResultSet;
	}

	/**
	 * Moves the cursor down one row from its current position.
	 *
	 * @return <code>true</code> if the new current row is valid;
	 *         <code>false</code> if there are no more rows
	 * @exception SQLException
	 *                if a database access error occurs
	 */
	public boolean next() throws SQLException {
		return queryResultSet.next();
	}

	/**
	 * return one record as Map
	 */
	public Map getRecord() throws SQLException {
		return getRecord(true);
	}

	/**
	 * return one record as Map
	 */
	public Map getRecord(boolean bToStr) throws SQLException {
		Map record = new HashMap();
		try {
			ResultSetMetaData meta = queryResultSet.getMetaData();
			int i = 0, count = meta.getColumnCount() + 1;
			for (i = 1; i < count; i++) {
				if (bToStr) {
					record.put(meta.getColumnLabel(i), zNull(queryResultSet
							.getString(i)));
				} else {
					Object column = queryResultSet.getObject(i);
					// if
					// (DBEnvConstant.getConfig("database.version").trim().equalsIgnoreCase(oracle10g))
					// {
					if (column instanceof java.sql.Date) {
						record.put(meta.getColumnLabel(i), queryResultSet
								.getTimestamp(i));
					} else {
						record.put(meta.getColumnLabel(i), column);
					}
					// } else {
					// record.put(meta.getColumnLabel(i),
					// queryResultSet.getObject(i));
					// }
				}
			}
		} catch (SQLException e) {
			e.setNextException(new SQLException(e.getMessage() + "&SQL="
					+ querySql.replaceAll("(\\s)+", " ")));
			throw e;
		}
		return record;
	}

	/**
	 * close resultSet and connection
	 */
	public void close() throws SQLException {
		try {
			if (queryResultSet != null) {
				queryResultSet.close();
			}

			if (queryStatement != null) {
				queryStatement.close();
			}

			if (queryConnection != null) {
				queryConnection.close();
			}
		} catch (SQLException e) {
			e.setNextException(new SQLException(e.getMessage() + "&SQL="
					+ querySql.replaceAll("(\\s)+", " ")));
			throw e;
		}
	}

	// added by Liuww 2007-11-05 end

	/**
	 * SELECT文を発行し、ロールバックする。<br>
	 * 結果をListで返す。Listの各要素はMapが格納されており、 keyにColumnLabelがvalueにObjectが設定されている。<br>
	 * key ： ラベル名 value ： カラム値
	 *
	 * @return DataSet SELECT結果のDataSet
	 */
	public DataSet executeQueryAsDataSet() throws Exception {
		long start = System.currentTimeMillis();
		Connection connection = null;
		DataSet result = null;

		try {
			connection = DbUtil.beginOptional(this.dbName, false);
			// データーベースーユーザ名を設定する
			connection = setSchemaForConnection(connection);
			result = executeQueryAsDataSet(connection);
		} catch (Exception e) {
			throw e;
		} finally {
			DbUtil.closeConnection(connection);
			logger.debug("TimeMillis=" + (System.currentTimeMillis() - start));
		}
		return result;
	}

	/**
	 * SELECT文を発行し、ロールバックする。<br>
	 * 結果をListで返す。Listの各要素はMapが格納されており、 keyにColumnLabelがvalueにObjectが設定されている。<br>
	 * key ： ラベル名 value ： カラム値 列名を取得したい場合はcolumnNamesにListを渡すこと。
	 *
	 * @param connection
	 *            データベースへのコネクション
	 *
	 * @return DataSet SELECT結果のDataSet
	 *
	 * @exception SQLException
	 *                sql例外
	 * @exception IOException
	 *                IO例外
	 */
	public DataSet executeQueryAsDataSet(Connection connection)
			throws SQLException, IOException {

		preparedSql.prepareParameter(this.parameterList);
		// SQLを実行する
		PreparedStatement statement = connection.prepareStatement(preparedSql
				.getSql());
		this.preparedSql.setParameter(statement, this.parameterList);
		ResultSet resultSet = statement.executeQuery();
		ResultSetMetaData meta = resultSet.getMetaData();
		List result = new ArrayList();
		int i = 0, count = meta.getColumnCount() + 1;
		Map record = null;
		while (resultSet.next()) {
			record = new HashMap();
			for (i = 1; i < count; i++) {
				// Edited by zhanjc 2007/03/08 Start
				// if
				// (DBEnvConstant.getConfig("database.version").trim().equalsIgnoreCase(oracle10g))
				// {
				if (resultSet.getObject(i) instanceof java.sql.Date) {
					record.put(meta.getColumnLabel(i), resultSet
							.getTimestamp(i));
				} else {
					record.put(meta.getColumnLabel(i), resultSet.getObject(i));
				}
				// } else {
				// record.put(meta.getColumnLabel(i), resultSet.getObject(i));
				// }
				// Edited by zhanjc 2007/03/08 End
			}
			result.add(record);
		}

		logger.debug("Count=" + result.size());
		List list = new ArrayList(count);
		for (i = 1; i < count; i++) {
			list.add(meta.getColumnName(i));
		}

		resultSet.close();
		statement.close();
		ListDataSet dataSet = new ListDataSet(result, list);

		return dataSet;
	}

	/**
	 * DML文を発行し、コミットする。<br>
	 *
	 * @return int JDBCのPreparedStatement.executeUpdate()の返り値
	 * @throws Exception
	 * @see java.sql.PreparedStatement#executeUpdate()
	 */
	public int executeStatement() throws Exception {
		Connection connection = null;
		int result = 0;
		try {
			connection = DbUtil.begin(this.dbName);
			// データーベースーユーザ名を設定する
			connection = setSchemaForConnection(connection);
			result = this.executeStatement(connection);
			DbUtil.commit(connection);
		} catch (Exception e) {
			DbUtil.safeRollback(connection);
			throw e;
		} finally {
		}
		return result;
	}

	/**
	 * DML文を発行する。（コミットしない）<br>
	 *
	 * @param connection
	 *            データベースへのコネクション
	 *
	 * @return int JDBCのPreparedStatement.executeUpdate()の返り値
	 *
	 * @exception SQLException
	 *                sql例外
	 * @exception IOException
	 *                IO例外
	 *
	 * @see java.sql.PreparedStatement#executeUpdate()
	 */
	public int executeStatement(Connection connection) throws SQLException,
			IOException {
		int type = this.preparedSql.sqlBrokenObj.getType();
		String completeSQL = null;
		try {
			if (type == DataAccessor.DML) {
				preparedSql.prepareParameter(this.parameterList);
				int result = 0;
				PreparedStatement statement = null;
				connection = setSchemaForConnection(connection);
				statement = connection.prepareStatement(preparedSql.getSql());
				completeSQL = this.preparedSql.setParameter(statement,
						this.parameterList);
				// DmlSqlLog.dbLog(this.id, completeSQL);
				result = statement.executeUpdate();
				statement.close();
				return result;
			} else if (type == DataAccessor.STORED) {
				return -1;
			} else if (type == DataAccessor.QUERY) {
				// SELECT FOR UPDATEのようなSQL文
				preparedSql.prepareParameter(this.parameterList);
				// SQLを実行する
				connection = setSchemaForConnection(connection);
				PreparedStatement statement = connection
						.prepareStatement(preparedSql.getSql());
				this.preparedSql.setParameter(statement, this.parameterList);
				ResultSet resultSet = statement.executeQuery();
				boolean hasRec = resultSet.next();
				resultSet.close();
				statement.close();
				if (hasRec) {
					return 1;
				} else {
					return 0;
				}
			} else {
				return -1;
			}
		} catch (SQLException e) {
			e.setNextException(new SQLException(e.getMessage() + "&SQL="
					+ completeSQL.replaceAll("(\\s)+", " ")));
			throw e;
		}

	}

	/**
	 * ストアドファンクションやストアドプロシージャを実行し、コミットする。
	 *
	 * @return int JDBCのPreparedStatement.executeUpdate()の返り値
	 *
	 * @exception SQLException
	 *                sql例外
	 */
	public int executeStoredStatement() throws Exception {
		Connection connection = null;
		try {
			connection = DbUtil.begin(this.dbName);
			// データーベースーユーザ名を設定する
			connection = setSchemaForConnection(connection);
			int result = this.executeStoredStatement(connection);
			DbUtil.commit(connection);
			return result;
		} catch (SQLException ex) {
			DbUtil.safeRollback(connection);
			throw ex;
		} catch (Exception ex) {
			DbUtil.safeRollback(connection);
			throw ex;
		} finally {
		}
	}

	/**
	 * ストアドファンクションやストアドプロシージャを実行する。（コミットしない）
	 *
	 * @param connection
	 *            データベースへのコネクション
	 *
	 * @return int JDBCのCallableStatement.execute()の返り値
	 *
	 * @exception SQLException
	 *                sql例外
	 * @exception IOException
	 *                IO例外
	 */
	public int executeStoredStatement(Connection connection)
			throws SQLException, IOException {
		Map outPara = preparedSql.prepareStoredParameter(this.parameterList,
				this.outputParameterList);
		CallableStatement statement = null;
		boolean result = false;
		connection = setSchemaForConnection(connection);
		statement = connection.prepareCall(preparedSql.getSql());
		this.preparedSql.setStoredParameter(statement, this.parameterList,
				outPara);
		result = statement.execute();
		this.preparedSql.getOutputParameter(statement, this.parameterList,
				this.outputParameterList, outPara);
		statement.close();
		if (result) {
			return 1;
		} else {
			return 0;
		}
	}

	/**
	 * SQL文とパラメータを書き出す。
	 */
	public String toString() {
		return this.preparedSql.toString();
	}

	/**
	 * スキーマを設定する。
	 *
	 * @param conn
	 *            データベースへのコネクション
	 *
	 * @return Connection データベースへのコネクションを返す
	 *
	 * @exception SQLException
	 *                sql例外
	 */
	public Connection setSchemaForConnection(Connection conn)
			throws SQLException {
		if (this.schemaName != null && !"".equals(this.schemaName)) {

			try {
				// DB2 set current_schema =
				// Oracle專用
				// 「schemaName」正しいの場合、スキーマを設定する
				PreparedStatement stmt = null;
				stmt = conn
						.prepareStatement("alter session set current_schema  = ?");
				stmt.setString(1, this.schemaName);
				stmt.executeUpdate();
				stmt.close();
			} catch (SQLException e) {
				DbUtil.safeRollback(conn);
				throw e;
			}
			// コネクションを返す
			return conn;
		}
		// コネクションを返す
		return conn;
	}

	/**
	 * 次回読込情報を取得する
	 *
	 * @return Integer 次回読込のレコード順番
	 */
	public Integer getNextRecord() {
		return nextRecord;
	}

	/**
	 * 将数据库更新操作添加到batch処理中（大数据量更新时用）， 不能在其他事务当中使用。
	 *
	 *
	 */
	public void addBatch() throws Exception {

		try {
			if (this.batchConn == null) {// 是否是第一次addBatch()
				this.batchConn = DbUtil.begin(this.dbName);
				// データーベースーユーザ名を設定する
				this.batchConn = setSchemaForConnection(this.batchConn);
			}

			int type = this.preparedSql.sqlBrokenObj.getType();
			if (type == DataAccessor.DML) {
				preparedSql.prepareParameter(this.parameterList);
				if (this.batchPst == null) {// 是否是第一次addBatch()
					this.batchPst = this.batchConn.prepareStatement(preparedSql
							.getSql());
				}

				String completeSQL = this.preparedSql.setParameter(
						this.batchPst, this.parameterList);
				// DmlSqlLog.dbLog(this.id, completeSQL);
				batchPst.addBatch();
			} else {
				logger.error("Only DML SQL can execute batch process!!!");
				DbUtil.closeConnection(this.batchConn);
			}
		} catch (Exception e) {
			logger.error(e.getMessage());
			DbUtil.closeConnection(this.batchConn);
			this.batchPst = null;
			this.batchConn = null;
			throw e;
		} finally {
		}

	}

	/**
	 * batch処理execute
	 *
	 * @return int[]
	 */
	public int[] executeBatch() throws Exception {

		int[] result = null;
		try {
			result = this.batchPst.executeBatch();
			this.batchPst.close();
			DbUtil.commit(this.batchConn);
		} catch (Exception e) {
			logger.error(e.getMessage());
			result = null;
			DbUtil.safeRollback(this.batchConn);
			throw e;
		} finally {
			this.batchPst = null;
			this.batchConn = null;
		}

		return result;
	}

	public Map getResultMap() throws SQLException, IOException, TorqueException {
		long start = System.currentTimeMillis();
		boolean bToStr = false;
		Connection connection = null;
		Map resultMap = new HashMap();
		try {
			connection = DbUtil.beginOptional(this.dbName, false);
			// データーベースーユーザ名を設定する
			connection = setSchemaForConnection(connection);
			preparedSql.prepareParameter(this.parameterList);
			// SQLを実行する
			PreparedStatement statement = connection
					.prepareStatement(preparedSql.getSql());
			querySql = this.preparedSql.setParameter(statement,
					this.parameterList);
			ResultSet resultSet = statement.executeQuery();
			ResultSetMetaData meta = resultSet.getMetaData();

			if (resultSet.next()) {
				int columnCount = meta.getColumnCount();
				for (int i = 1; i <= columnCount; i++) {
					if (bToStr) {
						resultMap.put(meta.getColumnLabel(i), zNull(resultSet
								.getString(i)));
					} else {

						if (resultSet.getObject(i) instanceof java.sql.Date) {
							resultMap.put(meta.getColumnLabel(i), resultSet
									.getTimestamp(i));
						} else {
							resultMap.put(meta.getColumnLabel(i), resultSet
									.getObject(i));
						}
					}
				}
			}
			resultSet.close();
			statement.close();
		} catch (SQLException e) {
			e.setNextException(new SQLException(e.getMessage() + "&SQL="
					+ querySql.replaceAll("(\\s)+", " ")));
			throw e;
		} catch (IOException e) {
			throw e;
		} catch (TorqueException e) {
			throw e;
		} finally {
			DbUtil.closeConnection(connection);
			logger.debug("TimeMillis=" + (System.currentTimeMillis() - start));
		}

		return resultMap;
	}

	/**
	 * zNull
	 *
	 * @param str
	 *            Character string
	 * @return After [ String ] edit
	 */
	public static String zNull(String str) {
		if (str == null) {
			return "";
		}
		if (str.equals("null")) {
			return "";
		}
		return str;
	}

}
